package tfts

import (
	"fmt"
	"github.com/expr-lang/expr"
	"github.com/spf13/viper"
	"math"
	"strconv"
	"strings"
)

var UpgradeChampion = false

var configs = make(map[string]*Config)

var exprEnv = make(map[string]interface{})

var buffParser = map[string]func(i int) *attrMeta{
	"ap":      AP,
	"ad":      AD,
	"ae":      AE,
	"as":      AS,
	"atk":     AtkAmp,
	"amp":     AMP,
	"uamp":    UnqAmp,
	"cc":      CritRate,
	"critAmp": CritAmp,
	"ar":      AR,
	"dr":      DR,
	"omp":     OMP,
	"hit":     Hit,
}

var showConfig = false

type Config struct {
	Name    string
	Phy     string `mapstructure:"Phy"` // 物理英雄,攻击力,攻速 字符串
	Mag     string `mapstructure:"Mag"` // 魔法英雄,攻击力,攻速 字符串
	Role    Role
	Mana    int            `mapstructure:"Mana"`
	Loop    bool           `mapstructure:"Loop"`
	Defence *DefenceConfig `mapstructure:"Def"`
	Skills  []SkillConfig  `mapstructure:"Skills"`
}

type DefenceConfig struct {
	Hp         int `mapstructure:"Hp"`
	Armor      int `mapstructure:"Ar"`
	Durability int `mapstructure:"Dr"`
	HealAmp    int `mapstructure:"Heal"`
	ShieldAmp  int `mapstructure:"Shield"`
	RecoverAmp int `mapstructure:"Recover"`
	HitRecover int `mapstructure:"Hit"`
	Omnivamp   int `mapstructure:"Steal"`
}

type SkillConfig struct {
	Dmg    string       `mapstructure:"Dmg"`  // 主伤害
	Dmg0   string       `mapstructure:"Dmg0"` // 副伤害
	Dmg1   string       `mapstructure:"Dmg1"` // 无加成伤害
	Mana   int          `mapstructure:"Mana"`
	Swing  int          `mapstructure:"Swing"`
	Shield string       `mapstructure:"Shield"`
	Heal   string       `mapstructure:"Heal"`
	Grow   string       `mapstructure:"Grow"`
	Buff   *BuffConfig  `mapstructure:"Buff"`
	Stack  *StackConfig `mapstructure:"Stack"`
}

type BuffConfig struct {
	Effect   string `mapstructure:"Effect"` // "Atk(200), AS(125)"
	Duration int    `mapstructure:"Duration"`
	Reduce   string `mapstructure:"Reduce"`
}

type StackConfig struct {
	Type  string `mapstructure:"Type"`
	Times int    `mapstructure:"Times"`
	Dmg   string `mapstructure:"Dmg"`
}

func ShowConfig() {
	showConfig = true
}

func AddVariable(key string, value interface{}) {
	exprEnv[key] = value
}

func LoadConfig(path string) map[string]Config {
	viper.SetConfigFile(path)
	viper.SetConfigType("yaml")

	if err := viper.ReadInConfig(); err != nil {
		panic(fmt.Errorf("读取配置文件失败: %v", err))
	}

	var rawConfig map[string]Config
	if err := viper.Unmarshal(&rawConfig); err != nil {
		panic(fmt.Errorf("解析配置失败: %v", err))
	}

	// 转换为结构化格式
	for heroName, heroCfg := range rawConfig {
		heroCfg.Name = heroName
		if showConfig {
			fmt.Printf("HeroName: %s\n", heroName)
			fmt.Printf("HeroCfg: %+v\n", heroCfg)
		}
		configs[heroName] = &heroCfg
	}

	return rawConfig
}

func parseDamage(dmg string) float64 {
	if len(dmg) == 0 || strings.ReplaceAll(dmg, " ", "") == "" {
		return 0
	}
	if res, err := strconv.ParseFloat(dmg, 64); err == nil {
		return res
	}
	program, err := expr.Compile(dmg, expr.Env(exprEnv))
	if err != nil {
		panic(fmt.Sprintf(`damage "%s" parse error: %v`, dmg, err))
	}
	output, err := expr.Run(program, exprEnv)
	if err != nil {
		panic(fmt.Sprintf(`damage "%s" eval error: %v`, dmg, err))
	}
	return output.(float64)
}

func (c *Config) RegisterBundle() *Bundle {
	bundle := &Bundle{championMeta: defaultChamp()}
	bundle.Role = c.Role
	meta, hType := c.Mag, Magic
	if len(c.Phy) != 0 {
		meta = c.Phy
		hType = Physics
	}
	bundle.dmgType = hType
	if len(meta) == 0 {
		panic("英雄属性不能为空")
	}
	splits := strings.Split(meta, " ")
	if len(splits) >= 1 {
		bundle.attack, _ = strconv.ParseFloat(splits[0], 64)
		if UpgradeChampion {
			bundle.attack *= 1.5
			bundle.attack = math.Floor(bundle.attack)
		}
	}
	if len(splits) >= 2 {
		bundle.speed, _ = strconv.ParseFloat(splits[1], 64)
	} else {
		// 默认攻速0.75
		bundle.speed = 0.75
	}
	bundle.initMana = c.Mana

	if c.Defence != nil {
		bundle.fighter = c.Defence.transfer()
	}

	// 存在同名bundle时覆盖
	bundles[c.Name] = bundle

	if len(c.Skills) == 0 {
		return bundle
	}
	bundle.skill = c.Skills[0].Create(hType, c.Defence != nil)
	head := bundle.skill
	current := bundle.skill
	for i := 1; i < len(c.Skills); i++ {
		current.next = c.Skills[i].Create(hType, c.Defence != nil)
		current = current.next
	}
	if c.Loop {
		current.next = head
	}
	bundle.championMeta.skill = bundle.skill
	return bundle
}

func (b BuffConfig) String() string {
	return fmt.Sprintf("Buff{Reduce: %s, Duration: %d, Effect: %s}", b.Reduce, b.Duration, b.Effect)
}

func (s SkillConfig) String() string {
	return fmt.Sprintf("Skill{Dmg: %s, Mana: %d, Swing: %d, Buff: %s}",
		s.Dmg, s.Mana, s.Swing, s.Buff)
}

func (s SkillConfig) Create(hType heroType, isFighter bool) *skill {
	meta := &skill{}
	meta.name = "Skill"
	if hType == Magic {
		meta.ApDmg = s.Dmg
	} else {
		meta.AdDmg = s.Dmg
		meta.ApDmg = s.Dmg0
	}
	meta.FixedDmg = s.Dmg1
	meta.mana = s.Mana
	meta.swing = s.Swing
	meta.Heal = s.Heal
	meta.Grow = s.Grow
	meta.Shield = s.Shield

	if s.Stack != nil {
		switch s.Stack.Type {
		case "attack":
			meta.stackBy = AtkStk
		case "cast", "":
			meta.stackBy = CastStk
		case "speed":
			meta.stackBy = AsStk
		default:
			panic(fmt.Sprintf("unknown stack type: %s", s.Stack.Type))
		}
		meta.times = s.Stack.Times
		if meta.times == 0 {
			meta.times = 1
		}
		meta.stackDmg = parseDamage(s.Stack.Dmg)
	}

	if s.Buff == nil {
		return meta
	}

	event := TimeGoE
	switch s.Buff.Reduce {
	case "time", "":
	case "attack":
		event = AttackE
	case "cast":
		event = AfterCastE
	default:
		panic(fmt.Sprintf("unknown reduce: %s", s.Buff.Reduce))
	}
	meta.buff = NewBuff(event, s.Buff.Duration)
	if isFighter {
		meta.buff.fighter = &fighter{}
	}
	meta.buff.parseAttr(s.Buff.Effect)

	return meta
}

func (d *DefenceConfig) transfer() *fighter {
	return &fighter{
		health:     d.Hp,
		armor:      d.Armor,
		dmgTaken:   100 - d.Durability,
		healthAmp:  100,
		healAmp:    100 + d.HealAmp,
		shieldAmp:  100 + d.ShieldAmp,
		recoverAmp: 100 + d.RecoverAmp,
		hitRecover: d.HitRecover,
		omnivamp:   d.Omnivamp,
	}
}
